Act {
	classvar last_input;
	classvar <>debug;
	classvar <>all;
	classvar <>min;
	var <>inputs;
	var <>priority;
	var <>blocking;
	var <>action;
	var <>pretty;

	*initClass { | debug = false |
		all = [];
		last_input = Set [ ];
		this.debug = debug;
		min = 4!8;
	}

	*new{ | inputs, priority, blocking, action, pretty |
		^super.new.init( inputs, priority, blocking, action, pretty );
	}

	init{ | in, prio, block, act, pp |
		inputs   = in.asSet;
		priority = prio;
		blocking = block ? { | x | x.difference( inputs ) };
		action   = act;
		pretty   = pp;
		all = all ++ this;
	}

	check{ | state |
		^and(
			state.sect( inputs ).size == inputs.size,
			last_input.sect( state ).sect( inputs ) == Set [ ]
		)
	}

	*run{ | state |
		var state_set = Set [];
		var state_set_pristine, result;
		state.do{
			| x, i |
			if( x > min[ i ], {
				state_set.add( i );
			} )
		};
		state_set_pristine = state_set.copy;
		result = all.sort{
			| x, y |
			x.priority > y.priority
		}.collect{
			| x |
			[
				x.pretty,
				if( x.check( state_set ), {
					state_set = x.blocking.value( state_set );
					x.action.value( state_set )
				}, {
					false } ) ] };
		if(
			and(
				debug,
				result.select{ | x | x[ 1 ] != false }.size != 0
			),
			{ result.postln } );
		last_input = state_set_pristine;
	}
}
